#include <stdio.h>
#include <conio.h>
#include <iostream>

#include <Windows.h>

#include "cFileIO.h"

using namespace std;

#define BUFFERSIZE (1*1024*1024)
#define BUFFERSIZEMAX ((DWORDLONG)4*1024*1024*1024)


#if defined(DEBUG) | defined(_DEBUG)

#define FILEIN  "test_files\\1.mp3"
#define FILEOUT "test_files\\2"

#else

#define FILEOUT argv[2]
#define FILEIN  argv[1]

#endif

void ErrorExit(cFileIO *io) {
	DWORD error_code;
	const char *message = io->GetErrorInformation(&error_code);
	cout << message;
	io->CloseAllHeandles();
	delete io;
	_getch();
    ExitProcess(error_code);
}


int main(int argc, char *argv[]) {
	
	#if !( defined(DEBUG) | defined(_DEBUG) )
	
	if(argc != 3) {
		cout << "Wrong parameters list" << endl;
		_getch();
		return 0;
	}
	
	#endif
	
	HANDLE hFileIn, hFileOut;
	HANDLE hMapFileIn, hMapFileOut;
	DWORD FileSizeInHigh, FileSizeInLow;
	DWORDLONG FileSizeIn;
	char *buffer_in, *buffer_out;
	
	cFileIO *IOSystem = new cFileIO;
	
	hFileIn = IOSystem->OpenFile(FILEIN, IO_READ, &FileSizeInHigh, &FileSizeInLow);
	if(hFileIn == INVALID_HANDLE_VALUE)
		ErrorExit(IOSystem);
	FileSizeIn = (DWORDLONG) FileSizeInHigh * BUFFERSIZEMAX + FileSizeInLow;

	hMapFileIn = IOSystem->CreateMappingOfFile(hFileIn);
	if(hMapFileIn == NULL)
		ErrorExit(IOSystem);
	
	hFileOut = IOSystem->OpenFile(FILEOUT, IO_READWRITE, &FileSizeInHigh, &FileSizeInLow);
	if(hFileOut == INVALID_HANDLE_VALUE)
		ErrorExit(IOSystem);

	hMapFileOut = IOSystem->CreateMappingOfFile(hFileOut, FileSizeInHigh, FileSizeInLow);
	if(hMapFileOut == NULL)
		ErrorExit(IOSystem);
	
	DWORDLONG counter = 0;
	DWORD counter_high = 0;
	while(FileSizeIn > counter_high * BUFFERSIZEMAX + counter) {
		
		if(counter >= BUFFERSIZEMAX) {
			counter -= BUFFERSIZEMAX;
			counter_high = 1;
		}
		
		buffer_in = IOSystem->Map(hMapFileIn, counter_high, counter, min(BUFFERSIZE, FileSizeIn - (counter_high * BUFFERSIZEMAX + counter)));
		if(buffer_in == NULL)
			ErrorExit(IOSystem);
		buffer_out = IOSystem->Map(hMapFileOut, counter_high, counter, min(BUFFERSIZE, FileSizeIn - (counter_high * BUFFERSIZEMAX + counter)));
		if(buffer_out == NULL)
			ErrorExit(IOSystem);
		
		memcpy(buffer_out, buffer_in, min(BUFFERSIZE, FileSizeIn - (counter_high * BUFFERSIZEMAX + counter)));
		
		counter += BUFFERSIZE;
	}

	delete IOSystem;
	
	cout << endl << "Finished" << endl << "Press any key...";
	
	_getch();
}